package com.yx.aop.aspect;

import com.alibaba.fastjson.JSON;
import com.yx.aop.annotation.LogRecord;
import com.yx.entity.SysLog;
import com.yx.mapper.SysLogMapper;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author  zcz
 * @desc    日志录入aop实现类
 * @time    2019/4/10
 * */
@Aspect
@Component
@Slf4j
public class LogAspect {
    @Autowired
    SysLogMapper sysLogMapper;

    /**
     * 此处的切点是注解的方式，也可以用包名的方式达到相同的效果
     * '@Pointcut("execution(* com.wwj.springboot.service.impl.*.*(..))")'
     */
    @Pointcut("@annotation(com.yx.aop.annotation.LogRecord)")
    public void operationLog(){}


    /**
     * 环绕增强，相当于MethodInterceptor
     */
    @Around("operationLog()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object res = null;
        long time = System.currentTimeMillis();
        try {
            res =  joinPoint.proceed();
            time = System.currentTimeMillis() - time;
            return res;
        } finally {
            try {
                //方法执行完成后增加日志
                //addOperationLog(joinPoint,res,time);
            }catch (Exception e){
               log.error("异常:",e.getStackTrace());
            }
        }
    }

    private void addOperationLog(JoinPoint joinPoint, Object res, long time){
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //获取操作系统和浏览器，兼容各个浏览器
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
        Browser browser = userAgent.getBrowser();
        OperatingSystem os = userAgent.getOperatingSystem();
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        SysLog log = new SysLog();
        log.setRunTime(time);
        log.setReturnValue(JSON.toJSONString(res));
        log.setIp(request.getRemoteAddr());
        log.setUrl(request.getRequestURI());
        log.setArgs(JSON.toJSONString(joinPoint.getArgs()));
        log.setCreateTime(new Date());
        log.setMethod(signature.getDeclaringTypeName() + "." + signature.getName());
        //shiro中取用户
        //operationLog.setCreater(ShiroUserUtil.getUserName());
        log.setBrowser(String.valueOf(browser));
        log.setOs(String.valueOf(os));
        LogRecord annotation = signature.getMethod().getAnnotation(LogRecord.class);
        if(annotation != null){
            log.setDescription(getDetail(((MethodSignature)joinPoint.getSignature()).getParameterNames(),joinPoint.getArgs(),annotation));
            log.setType(annotation.type().getValue());
            log.setUnit(annotation.unit().getValue());
        }
        LogAspect.log.info("记录日志:" + log.toString());
        sysLogMapper.insert(log);
    }

    /**
     * 对当前登录用户和占位符处理
     * @param argNames 方法参数名称数组
     * @param args 方法参数数组
     * @param annotation 注解信息
     * @return 返回处理后的描述
     */
    private String getDetail(String[] argNames, Object[] args, LogRecord annotation){
        Map<Object, Object> map = new HashMap<>(4);
        for(int i = 0;i < argNames.length;i++){
            map.put(argNames[i],args[i]);
        }

        String detail = annotation.desc();
        try {
            detail = annotation.desc();
            for (Map.Entry<Object, Object> entry : map.entrySet()) {
                Object k = entry.getKey();
                Object v = entry.getValue();
                detail = detail.replace("{{" + k + "}}", JSON.toJSONString(v));
            }
        }catch (Exception e){
            log.error("异常:",e.getStackTrace());
        }
        return detail;
    }

    @Before("operationLog()")
    public void doBeforeAdvice(JoinPoint joinPoint){
    }

    /**
     * 处理完请求，返回内容
     * @param ret
     */
    @AfterReturning(returning = "ret", pointcut = "operationLog()")
    public void doAfterReturning(Object ret) {
        System.out.println("方法的返回值 : " + ret);
    }

    /**
     * 后置异常通知
     */
    @AfterThrowing("operationLog()")
    public void throwss(JoinPoint jp){
        System.out.println("方法异常时执行.....");
    }


    /**
     * 后置最终通知,final增强，不管是抛出异常或者正常退出都会执行
     */
    @After("operationLog()")
    public void after(JoinPoint jp){
    }

}